package com.wangyadong.hobby.javanetwork.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

public class NioTest1 {

    public static void main(String[] args) {
        try {
            byte[] rotation = rotation();
            //构建服务器
            ServerSocketChannel socketChannel = ServerSocketChannel.open();
            ServerSocket ss = socketChannel.socket();
            //绑定ip和端口号
            SocketAddress address = new InetSocketAddress(19);
            //绑定地址和端口
            ss.bind(address);
            //设置服务器为非阻塞
            socketChannel.configureBlocking(false);
//            //监听客户端数据
            //在传统Io中 每个请求都会派发一个线程进行处理 使用NIO之后 我们可以使用Selector
            Selector open = Selector.open();
            //像服务器中注册选择器
            //有个疑问是SocketChannel 和ServerSocketChannel 都可以对selector 进行注册
            // 为什么不能是op_write
            socketChannel.register(open, SelectionKey.OP_ACCEPT);
            while (true) {
                open.select();
                Set<SelectionKey> selectionKeys = open.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey next = iterator.next();
                    iterator.remove();
                    SelectableChannel channel = next.channel();
                    if (next.isAcceptable()) {
                        //表示服务器类型，只有服务器类型才可以监听请求
                        ServerSocketChannel serverSocketChannel = (ServerSocketChannel) channel;
                        SocketChannel accept1 = serverSocketChannel.accept();
                        System.out.println(" accept form --> " + accept1);
                        accept1.configureBlocking(false);
                        SelectionKey register = accept1.register(open, SelectionKey.OP_WRITE);
                        ByteBuffer allocate = ByteBuffer.allocate(74);
                        allocate.put(rotation, 0, 72);
                        allocate.put((byte) '\r');
                        allocate.put((byte) '\n');
                        allocate.flip();
                        register.attach(allocate);
                        System.out.println(allocate);
                    } else if (next.isWritable()) {
                        //向客户端写入还是向服务器写入
                        SocketChannel socketChannel1 = (SocketChannel) channel;
                        ByteBuffer attachment = (ByteBuffer) next.attachment();
                        //要取反
                        if (!attachment.hasRemaining()) {
                            attachment.rewind();//用下一行重新填充缓存区
                            byte first = attachment.get();//获取第一个字符
                            int position = first - ' ' + 1;
                            attachment.put(rotation, position, 72);
                            attachment.put((byte) '\r');
                            attachment.put((byte) '\n');
                        }
                        socketChannel1.write(attachment);

                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static byte[] rotation() {
        byte[] rotation = new byte[95 * 2];
        for (byte i = ' '; i < '~'; i++) {
            rotation[i - ' '] = i;
            rotation[i + 95 - ' '] = i;
        }
        return rotation;

    }
}
